//http://linas.org/art-gallery/escape/escape.html
// Paxinum solution http://stackoverflow.com/questions/369438/smooth-spectrum-for-mandelbrot-set-rendering

import java.awt.Color;
import java.awt.Point;
import java.awt.image.BufferedImage;

public class MandelbrotRender{
	
	int totalWidth;
	int totalHeight;
	double MinRe;
	double MaxRe;
	double MinIm;
	double MaxIm;
	boolean verbose;
	double zoom;
	double step;
	
	public MandelbrotRender(int totalWidth, int totalHeight, boolean verbose) {
		this.totalWidth = totalWidth;
		this.totalHeight = totalHeight;
		this.MinRe = -2.0;
		this.MaxRe = 1.0;
		this.MinIm = -1.15;
		this.verbose = verbose;
		this.zoom = 1;		
		this.MaxIm = MinIm+(MaxRe-MinRe)*totalHeight/totalWidth;
		this.step = 0;
	}

	public void render(BufferedImage canvas, int boxXPosition, int boxYPosition){
		int height = canvas.getHeight();
		int width = canvas.getWidth();

		double Re_factor = (MaxRe-MinRe)/(totalWidth-1)*zoom;
		double Im_factor = (MaxIm-MinIm)/(totalHeight-1)*zoom;
		int MaxIterations = 40;
		//System.out.println(boxXPosition + " "  + boxYPosition);

		for(int y=boxYPosition; y<height+boxYPosition; ++y){
		    
		    for(int x=boxXPosition; x<width+boxXPosition; ++x){
		    	//System.out.println(x);
		    	int n;
		    	double c_im = MaxIm - y*Im_factor;
		        double c_re = MinRe + x*Re_factor;
		        double Z_re = c_re;
		        double Z_im = c_im;		       
		        boolean isInside = true;
		        for(n=0; n<MaxIterations; ++n){
		        	double Z_re2 = Z_re*Z_re, Z_im2 = Z_im*Z_im;
		            if(Z_re2 + Z_im2 > 4){
		            	isInside = false;
		            	break;
		            }
				    Z_im = 2*Z_re*Z_im + c_im;
				    Z_re = Z_re2 - Z_im2 + c_re;
		        }
		        int drawX = x-boxXPosition;
		        int drawY = y-boxYPosition;
		        if(isInside){ 
		        	canvas.setRGB(drawX, drawY, Color.BLACK.getRGB());
		        }
		        else{
			        double modulus = Math.sqrt((Z_re*Z_re + Z_im*Z_im));
			        double mu = n + 1 - Math.log(Math.log(modulus)) / Math.log(2.0);	
			        float colorSelected = (float) (4 * mu/MaxIterations);
			        colorSelected -= step;
			        //System.out.println(colorSelected);
			        canvas.setRGB(drawX, drawY, Color.HSBtoRGB(colorSelected,0.9f,0.9f));
		        }

		    }
		    
		}
		if(verbose){
			for(int i=0; i<width; i++){
				canvas.setRGB(i, 0, Color.green.getRGB());
				canvas.setRGB(i, height-1, Color.red.getRGB());
			}
		}	
		
		if(verbose){
			for(int i=0; i<height; i++){
				canvas.setRGB(0, i, Color.blue.getRGB());
				canvas.setRGB(width-1, i, Color.white.getRGB());
			}
		}	
		
	}

	public void updateZoom(Point latest) {
		//System.out.println("Latest point is..." + latest);		
		
		zoom *= 0.94;
		step += 0.05;
		
		step %= 1;
		
		
		int awayFromCenterX = (latest.x-totalWidth/2)+totalWidth/9;
		int awayFromCenterY = (latest.y-totalHeight/2)+totalHeight/9;
		
		double moveX = awayFromCenterX * zoom * 0.001;
		double moveY = awayFromCenterY * zoom * 0.001;
		
		//System.out.println("moveX = " + moveX + "moveY = " +  moveY);
		
		
			
		MinRe += moveX;
		MaxRe += moveX;
		MinIm -= moveY;
		MaxIm -= moveY;
		
	
		
		
		
	}
	
}